<template>
  <div class="vector-annotation-section">
    <!-- 禁用状态提示 -->
    <div v-if="!isEnabled" class="vector-disabled-notice">
      <div class="disabled-notice-content">
        <DisabledIcon :size="24" class="disabled-icon-large" />
        <h4>向量标注功能不可用</h4>
        <p>只有匹配成功、向量中或完成状态的颜色才能进行向量标注</p>
        <p>
          当前状态：<span class="status-indicator" :class="getStatusBadgeClass(currentStatus)">
            {{ getStatusText(currentStatus) }}
          </span>
        </p>
      </div>
    </div>

    <!-- 特征矩阵 -->
    <div v-else class="feature-matrix" ref="containerRef">
      <div class="matrix-header">
        <div class="image-preview">
          <div class="image-grid">
            <div
              v-for="(imageData, index) in getPreviewImages()"
              :key="index"
              class="image-slot"
              :class="{ 'has-image': imageData.image }"
            >
              <img
                v-if="imageData.image"
                :src="imageData.image"
                :alt="`匹配图片 ${index + 1}`"
                @click="toggleImageZoom(index)"
                :class="{ zoomable: true }"
              />
              <div v-else class="placeholder">图片{{ index + 1 }}</div>
              <div v-if="imageData.angle" class="angle-badge">
                {{ getAngleDisplayName(imageData.angle) }}
              </div>
            </div>
          </div>
        </div>
        <div class="matrix-content">
          <h4>特征矩阵（自动值 vs 人工值）</h4>

          <div v-if="loading" class="loading-placeholder">正在加载特征配置...</div>

          <div v-else-if="dynamicFeatures.length === 0" class="empty-placeholder">暂无特征配置</div>

          <div v-else class="feature-list">
            <div
              v-for="feature in dynamicFeatures"
              :key="feature.key"
              class="feature-item"
              :class="layoutClass"
            >
              <div class="feature-label">
                {{ feature.label }}
                <span class="required-mark">*</span>
              </div>
              <div class="feature-auto">默认：{{ getFeatureAutoValue(feature.key) }}</div>
              <div class="feature-manual">
                <!-- 下拉框模式 -->
                <div v-if="!feature.isAdding" class="dropdown-mode">
                  <select
                    :value="getDisplayValue(feature.key)"
                    class="select"
                    @change="onFeatureChange(feature.key, $event.target.value)"
                  >
                    <option value="">{{ getFeatureAutoValue(feature.key) }}</option>
                    <option
                      v-for="option in getFeatureOptions(feature.key)"
                      :key="option.id || option"
                      :value="option.name || option"
                    >
                      {{ option.name || option }}
                    </option>
                  </select>
                  <button
                    class="btn btn-add"
                    @click="startAddingFeature(feature.key)"
                    title="添加新选项"
                  >
                    +
                  </button>
                </div>

                <!-- 输入框模式 -->
                <div v-else class="input-mode">
                  <input
                    v-model="feature.newValue"
                    type="text"
                    class="input"
                    :placeholder="`输入新的${feature.label}`"
                    @keyup.enter="confirmAddFeature(feature.key)"
                    ref="featureInput"
                  />
                  <button
                    class="btn btn-confirm"
                    @click="confirmAddFeature(feature.key)"
                    title="确认"
                  >
                    <CheckIcon :size="14" />
                  </button>
                  <button
                    class="btn btn-cancel"
                    @click="cancelAddingFeature(feature.key)"
                    title="取消"
                  >
                    ×
                  </button>
                </div>
              </div>
              <button class="btn btn-small" @click="resetFeature(feature.key)">⟲ 回退</button>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 工具条 -->
    <div v-if="isEnabled" class="vector-toolbar">
      <div class="toolbar-left">
        <button
          class="btn btn-accept btn-compact"
          :disabled="!canAccept || isProcessing"
          :class="{ processing: isProcessing && processingButton === 'completed' }"
          @click="handleAccept"
        >
          接受
        </button>
        <button
          class="btn btn-vectoring btn-compact"
          :disabled="isProcessing"
          :class="{ processing: isProcessing && processingButton === 'vectoring' }"
          @click="handleStore"
        >
          暂存
        </button>
        <div v-if="!canAccept && !isProcessing" class="accept-hint">请填写所有向量维度</div>
        <div v-if="isProcessing" class="processing-hint">正在处理中...</div>
      </div>
      <div class="toolbar-right">
        <button class="btn btn-reset btn-compact" @click="resetAllFeatures">全部回退</button>
      </div>
    </div>
  </div>

  <!-- 重复检查弹窗 -->
  <DuplicateCheckDialog
    :visible="showDuplicateDialog"
    :conflict-color-info="duplicateColorInfo"
    :duplicate-dimensions="dimensionsResult?.data?.duplicate_dimensions"
    @close="closeDuplicateDialog"
  />

  <!-- 图片放大镜 -->
  <div v-if="zoomedImageIndex !== null" class="image-zoom-overlay" @click="closeImageZoom">
    <div class="image-zoom-container" @click.stop>
      <img
        :src="getZoomedImageSrc()"
        :alt="`放大图片 ${zoomedImageIndex + 1}`"
        class="zoomed-image"
      />
      <button class="zoom-close-btn" @click="closeImageZoom" title="关闭">×</button>
    </div>
  </div>
</template>

<script>
import { ref, onMounted, nextTick, watch, computed } from 'vue'
import {
  getFeatureConfig,
  addDictionaryItem,
  getFeatureOptions as getFeatureOptionsFromApi,
} from '../api/featureApi'
import { getColorDimensions, saveColorDimensions } from '../api/vectorApi'
import { matchingStyleStatus } from '../api/styleApi'
import { post } from '../utils/request'
import { DisabledIcon, CheckIcon } from './icons'
import { getFullImageUrl } from '../utils/imageUtils'
import { getAngleDisplayName } from '../utils/angleUtils'
import DuplicateCheckDialog from './DuplicateCheckDialog.vue'

export default {
  name: 'VectorAnnotation',
  components: {
    DisabledIcon,
    CheckIcon,
    DuplicateCheckDialog,
  },
  props: {
    currentAnnotation: {
      type: Object,
      default: null,
    },
    isEnabled: {
      type: Boolean,
      default: false,
    },
    currentStatus: {
      type: String,
      default: '',
    },
    dictionaries: {
      type: Object,
      default: () => ({}),
    },
    batchId: {
      type: String,
      default: '',
    },
    // 添加颜色数据属性，用于获取图片信息
    colorData: {
      type: Object,
      default: null,
    },
    // 添加图片数据属性，用于向量标注的图片预览
    images: {
      type: Object,
      default: () => ({}),
    },
  },
  emits: ['reset-feature', 'add-tag', 'remove-tag', 'annotation-saved'],
  setup(props, { emit }) {
    const loading = ref(false)
    const dynamicFeatures = ref([])
    const featureOptions = ref({})
    const featureInput = ref(null)
    const containerRef = ref(null)
    const layoutClass = ref('layout-wide')

    // 添加加载状态
    const isProcessing = ref(false)
    const processingButton = ref(null)

    // 重复检查弹窗状态
    const showDuplicateDialog = ref(false)
    const duplicateColorInfo = ref(null)
    const dimensionsResult = ref(null) // 记录正在处理的按钮类型

    // 图片放大状态
    const zoomedImageIndex = ref(null)

    // 获取颜色的款式ID（适配新的数据结构）
    const getColorStyleId = color => {
      if (color.style_code && typeof color.style_code === 'object' && 'value' in color.style_code) {
        return color.style_code.value || ''
      }
      if (color.style_id && typeof color.style_id === 'object' && 'value' in color.style_id) {
        return color.style_id.value || ''
      }
      return color.style_code || color.style_id || ''
    }

    // 安全地获取字段值（适配新旧数据结构）
    const getFieldValue = (obj, fieldName) => {
      if (!obj || !obj[fieldName]) {
        // 对于数组字段，返回空数组
        if (['angles', 'missingAngles'].includes(fieldName)) {
          return []
        }
        return ''
      }
      const field = obj[fieldName]
      if (typeof field === 'object' && 'value' in field) {
        return field.value || ''
      }
      return field || ''
    }

    // 计算属性：检查所有向量维度是否都有值
    const canAccept = computed(() => {
      if (!props.currentAnnotation || !dynamicFeatures.value.length) {
        console.log('canAccept: 缺少必要数据', {
          hasCurrentAnnotation: !!props.currentAnnotation,
          dynamicFeaturesLength: dynamicFeatures.value.length,
        })
        return false
      }

      // 检查所有向量维度是否都有值（所有字段都是必填的）
      const result = dynamicFeatures.value.every(feature => {
        const annotation = props.currentAnnotation[feature.key]
        if (!annotation) {
          console.log(`canAccept: 缺少 ${feature.key} 的注解数据`)
          return false
        }

        // 检查 manual 字段是否有值
        const manualValue = annotation.manual
        const hasValue = Array.isArray(manualValue)
          ? manualValue.length > 0
          : manualValue && manualValue.trim() !== ''

        console.log(`canAccept: ${feature.key} manual=${manualValue}, hasValue=${hasValue}`)
        return hasValue
      })

      console.log('canAccept 最终结果:', result)
      return result
    })

    // 响应式布局检测
    const updateLayout = () => {
      if (!containerRef.value) return

      const containerWidth = containerRef.value.offsetWidth

      if (containerWidth >= 800) {
        layoutClass.value = 'layout-wide'
      } else if (containerWidth >= 650) {
        layoutClass.value = 'layout-medium'
      } else if (containerWidth >= 550) {
        layoutClass.value = 'layout-narrow'
      } else if (containerWidth >= 350) {
        layoutClass.value = 'layout-mobile'
      } else {
        layoutClass.value = 'layout-tiny'
      }
    }

    // 监听容器大小变化
    const resizeObserver = ref(null)

    onMounted(() => {
      if (containerRef.value) {
        updateLayout()

        // 使用 ResizeObserver 监听容器大小变化
        if (window.ResizeObserver) {
          resizeObserver.value = new ResizeObserver(updateLayout)
          resizeObserver.value.observe(containerRef.value)
        } else {
          // 降级方案：监听窗口大小变化
          window.addEventListener('resize', updateLayout)
        }
      }
    })

    // 清理监听器
    const cleanup = () => {
      if (resizeObserver.value) {
        resizeObserver.value.disconnect()
      }
      window.removeEventListener('resize', updateLayout)
    }

    // 加载特征配置
    const loadFeatureConfig = async () => {
      if (!props.batchId) return

      loading.value = true
      try {
        // 获取特征配置
        const featureConfig = await getFeatureConfig({ batchId: props.batchId })

        // 为每个特征添加状态属性
        dynamicFeatures.value = featureConfig.map(feature => ({
          ...feature,
          isAdding: false,
          newValue: '',
        }))

        // 获取特征选项数据
        const options = await getFeatureOptionsFromApi({
          features: featureConfig,
          batchId: props.batchId,
        })
        featureOptions.value = options
        console.log('加载的特征选项数据:', options)

        // 加载维度数据（如果有颜色数据）
        if (props.colorData && props.colorData.id) {
          try {
            console.log('colorData:', props.colorData)
            console.log('color_id:', props.colorData.id)

            // 确保获取到正确的 color_id（数字）
            const colorId =
              typeof props.colorData.id === 'object' ? props.colorData.id.value : props.colorData.id
            console.log('实际使用的 color_id:', colorId)

            const dimensionsData = await getColorDimensions(colorId)
            console.log('加载的维度数据:', dimensionsData)

            // 更新父组件的标注数据
            if (dimensionsData && props.currentAnnotation) {
              console.log('开始更新标注数据，currentAnnotation:', props.currentAnnotation)
              Object.keys(dimensionsData).forEach(key => {
                if (props.currentAnnotation[key]) {
                  // 将后端返回的维度数据转换为前端格式
                  const dimension = dimensionsData[key]
                  if (dimension && dimension.value !== undefined) {
                    // 将维度数据设置为 auto 值（默认值）
                    // 所有向量值都是单值，不再区分array/text类型
                    const autoValue = dimension.value || ''
                    console.log(`设置 ${key}: auto=${autoValue}, manual=${autoValue}`)
                    props.currentAnnotation[key].auto = autoValue
                    // 同时将 manual 设置为 auto 值，这样用户保持初始值时按钮可用
                    props.currentAnnotation[key].manual = autoValue
                  }
                } else {
                  console.log(`警告: currentAnnotation 中没有找到 ${key} 字段`)
                }
              })
              console.log('更新后的 currentAnnotation:', props.currentAnnotation)
            } else {
              console.log('无法更新标注数据:', {
                hasDimensionsData: !!dimensionsData,
                hasCurrentAnnotation: !!props.currentAnnotation,
                currentAnnotation: props.currentAnnotation,
              })
            }
          } catch (error) {
            console.log('没有找到维度数据，使用空数据:', error)
          }
        }
      } catch (error) {
        console.error('加载特征配置失败:', error)
      } finally {
        loading.value = false
      }
    }

    // 获取特征的自动值
    const getFeatureAutoValue = featureKey => {
      return props.currentAnnotation?.[featureKey]?.auto || ''
    }

    // 获取特征的下拉选项（过滤掉与自动值重复的选项）
    const getFeatureOptions = featureKey => {
      const options = featureOptions.value[featureKey] || []
      const autoValue = getFeatureAutoValue(featureKey)

      // 过滤掉与自动值相同的选项，避免重复
      const filteredOptions = options.filter(option => {
        const optionName = option.name || option
        return optionName !== autoValue
      })

      console.log(`获取特征选项 ${featureKey}:`, filteredOptions)
      return filteredOptions
    }

    // 获取下拉框的显示值
    const getDisplayValue = featureKey => {
      const annotation = props.currentAnnotation?.[featureKey]
      if (!annotation) return ''

      const manualValue = annotation.manual
      const autoValue = annotation.auto

      // 如果 manual 值等于 auto 值，返回空字符串（显示第一个选项）
      // 否则返回 manual 值
      return manualValue === autoValue ? '' : manualValue
    }

    // 特征值变化处理
    const onFeatureChange = (featureKey, value) => {
      if (props.currentAnnotation?.[featureKey]) {
        // 如果用户选择了空值（即选择显示 auto 值的选项），则将 manual 设置为空
        // 这样下拉框会显示 auto 值作为默认值
        props.currentAnnotation[featureKey].manual = value || ''
      }
    }

    // 开始添加新特征值
    const startAddingFeature = featureKey => {
      const feature = dynamicFeatures.value.find(f => f.key === featureKey)
      if (feature) {
        feature.isAdding = true
        feature.newValue = ''
        nextTick(() => {
          if (featureInput.value) {
            featureInput.value.focus()
          }
        })
      }
    }

    // 确认添加新特征值
    const confirmAddFeature = async featureKey => {
      const feature = dynamicFeatures.value.find(f => f.key === featureKey)
      if (feature && feature.newValue.trim()) {
        try {
          console.log(`正在添加新的特征值: ${featureKey} - ${feature.newValue.trim()}`)

          // 调用API将新值添加到字典中
          const result = await addDictionaryItem({
            category: getCategoryFromFeatureKey(featureKey),
            name: feature.newValue.trim(),
            batchId: props.batchId,
          })

          if (result.success) {
            console.log('添加成功，正在重新加载特征选项...')

            // 更新当前选择的值
            if (props.currentAnnotation?.[featureKey]) {
              props.currentAnnotation[featureKey].manual = feature.newValue.trim()
            }

            // 重新加载特征选项以包含新添加的项
            await loadFeatureConfig()

            console.log('特征选项重新加载完成')
          } else {
            console.error('添加失败:', result.message)
          }
        } catch (error) {
          console.error('添加新特征值失败:', error)
        }

        // 重置添加状态
        feature.isAdding = false
        feature.newValue = ''
      } else {
        console.log('输入值为空，取消添加')
        cancelAddingFeature(featureKey)
      }
    }

    // 根据特征键获取字典类别
    const getCategoryFromFeatureKey = featureKey => {
      // 根据新的API规范，直接使用特征键作为字典类型
      const categoryMap = {
        clothingType: 'clothingType',
        color: 'color',
        pattern: 'pattern',
        material: 'material',
        sleeveType: 'sleeveType',
        collarType: 'collarType',
      }
      return categoryMap[featureKey] || featureKey
    }

    // 取消添加新特征值
    const cancelAddingFeature = featureKey => {
      const feature = dynamicFeatures.value.find(f => f.key === featureKey)
      if (feature) {
        feature.isAdding = false
        feature.newValue = ''
      }
    }

    // 处理接受按钮点击
    const handleAccept = async () => {
      if (!canAccept.value || isProcessing.value) {
        return
      }

      await handleAnnotationSubmit('completed')
    }

    // 处理暂存按钮点击
    const handleStore = async () => {
      if (isProcessing.value) {
        return
      }

      await handleAnnotationSubmit('vectoring')
    }

    // 统一的标注提交处理
    const handleAnnotationSubmit = async statusType => {
      if (!props.colorData || !props.currentAnnotation) {
        console.error('缺少必要的数据')
        return
      }

      try {
        // 设置处理状态
        isProcessing.value = true
        processingButton.value = statusType

        // 准备维度数据（根据接口规格，只需要维度值）
        const dimensionsData = {}

        // 转换特征数据格式，只保留维度值
        Object.keys(props.currentAnnotation).forEach(key => {
          if (key !== 'batchId' && props.currentAnnotation[key]) {
            const manualValue = props.currentAnnotation[key].manual
            if (manualValue !== undefined && manualValue !== '') {
              // 如果字符串为空，则跳过
              if (manualValue === '') {
                return
              }
              dimensionsData[key] = manualValue
            }
          }
        })

        console.log('提交维度数据:', dimensionsData)

        // 1. 调用 dimensions 接口保存维度数据
        // 确保获取到正确的 color_id（数字）
        const colorId =
          typeof props.colorData.id === 'object' ? props.colorData.id.value : props.colorData.id
        const dimensionsResponse = await saveColorDimensions(colorId, dimensionsData)
        dimensionsResult.value = dimensionsResponse

        console.log('维度保存结果:', dimensionsResult.value)

        // 2. 调用 matching-status 接口更新状态
        // 使用 color_id 而不是 colorKey
        const statusResponse = await matchingStyleStatus(colorId, statusType)
        const statusResult = statusResponse.data || statusResponse

        console.log('状态更新结果:', statusResult)

        // 3. 显示成功消息（只有在没有冲突的情况下）
        const actionText = statusType === 'completed' ? '接受' : '暂存'
        window.$toast?.showSuccess(`${actionText}成功`)

        // 4. 触发父组件更新（如果需要）
        emit('annotation-saved', {
          colorId,
          status: statusType,
          annotation: dimensionsData,
        })
      } catch (error) {
        console.error('提交标注失败:', error)
        console.log('错误对象结构:', error)
        console.log('error.response:', error.response)
        console.log('error.response?.data:', error.response?.data)

        const actionText = statusType === 'completed' ? '接受' : '暂存'

        // 检查是否是业务错误（如冲突检查失败）
        // 由于 request.js 会将业务错误码包装在 error.response.data 中
        if (error.response && error.response.data && error.response.data.code === 400) {
          const errorData = error.response.data
          console.log('检测到业务错误码400:', errorData)
          if (errorData.data && errorData.data.conflict_color) {
            console.log('检测到冲突颜色信息:', errorData.data.conflict_color)
            // 重复检查错误，显示冲突颜色详情
            duplicateColorInfo.value = errorData.data.conflict_color
            showDuplicateDialog.value = true
            return // 不显示错误提示
          }
        }

        // 其他错误，显示普通错误消息
        window.$toast?.showError(`${actionText}失败`, error.message || '未知错误')
      } finally {
        // 重置处理状态
        isProcessing.value = false
        processingButton.value = null
      }
    }

    // 处理全部回退
    const resetAllFeatures = () => {
      if (!props.currentAnnotation) {
        return
      }

      // 重置所有特征字段的 manual 值为 auto 值
      dynamicFeatures.value.forEach(feature => {
        const annotation = props.currentAnnotation[feature.key]
        if (annotation) {
          // 重置为 auto 值，这样用户保持初始值时按钮可用
          annotation.manual = annotation.auto || ''
        }
      })

      console.log('已重置所有向量维度到默认值')
    }

    const getStatusText = status => {
      const statusMap = {
        pending: '待匹配',
        success: '匹配成功',
        failed: '匹配失败',
        empty: '放弃',
        vectoring: '向量中',
        completed: '完成',
      }
      return statusMap[status] || status
    }

    const getStatusBadgeClass = status => {
      const classMap = {
        pending: 'badge-pending',
        success: 'badge-success',
        failed: 'badge-error',
        empty: 'badge-empty',
        vectoring: 'badge-vectoring',
        completed: 'badge-completed',
      }
      return classMap[status] || 'badge-pending'
    }

    const resetFeature = featureName => {
      emit('reset-feature', featureName)
    }

    // 关闭重复检查弹窗
    const closeDuplicateDialog = () => {
      showDuplicateDialog.value = false
      duplicateColorInfo.value = null
      dimensionsResult.value = null
    }

    // 获取预览图片（前4张，跳过空图片）
    const getPreviewImages = () => {
      // 优先使用 images prop，如果没有则尝试从 colorData 中获取
      let imageData = props.images

      console.log('VectorAnnotation: props.images', props.images)
      console.log('VectorAnnotation: props.colorData', props.colorData)

      if (!imageData || Object.keys(imageData).length === 0) {
        // 如果没有 images prop，尝试从 colorData 中获取
        if (props.colorData && props.colorData.images) {
          imageData = props.colorData.images
        } else {
          console.log('VectorAnnotation: 没有图片数据', {
            images: props.images,
            colorData: props.colorData,
          })
          // 返回4个空位
          return Array(4).fill({ image: null, angle: null })
        }
      }

      console.log('VectorAnnotation: 图片数据', imageData)

      // 处理图片数据格式
      let validImages = []

      if (Array.isArray(imageData)) {
        // 数组格式：[{ angle: 'A', url: '/path/to/image.jpg' }]
        validImages = imageData
          .filter(item => item && item.angle && item.url)
          .map(item => ({
            image: getFullImageUrl(item.url),
            angle: item.angle,
          }))
      } else if (typeof imageData === 'object') {
        // 对象格式：{ "F": "/images/K-001-01-F.jpg", "B": "/images/K-001-01-B.jpg" }
        validImages = Object.entries(imageData)
          .filter(([angle, url]) => angle && url)
          .map(([angle, url]) => ({
            image: getFullImageUrl(url),
            angle: angle,
          }))
      }

      console.log('VectorAnnotation: 有效图片数据', validImages)

      // 取前4张，如果不足4张则补充空位
      const result = validImages.slice(0, 4)

      // 如果不足4张，补充空位
      while (result.length < 4) {
        result.push({ image: null, angle: null })
      }

      return result
    }

    onMounted(async () => {
      if (props.isEnabled && props.batchId) {
        await loadFeatureConfig()
      }
    })

    // 监听相关props的变化，当颜色数据或批次ID变化时重新加载数据
    watch(
      () => [props.colorData?.id, props.batchId, props.isEnabled],
      async ([newColorId, newBatchId, newIsEnabled], [oldColorId, oldBatchId, oldIsEnabled]) => {
        // 当颜色ID变化时，重新加载数据
        if (newColorId !== oldColorId && newIsEnabled && newBatchId) {
          console.log('颜色数据变化，重新加载特征配置:', {
            oldColorId,
            newColorId,
            newBatchId,
          })
          await loadFeatureConfig()
        }
        // 当批次ID变化时，重新加载数据
        else if (newBatchId !== oldBatchId && newIsEnabled && newBatchId) {
          console.log('批次ID变化，重新加载特征配置:', {
            oldBatchId,
            newBatchId,
          })
          await loadFeatureConfig()
        }
        // 当启用状态变化时，如果变为启用状态且有批次ID，则加载数据
        else if (!oldIsEnabled && newIsEnabled && newBatchId) {
          console.log('向量标注功能启用，加载特征配置:', {
            newBatchId,
          })
          await loadFeatureConfig()
        }
      },
      { immediate: false }
    )

    // 监听启用状态变化，确保在启用时加载数据
    watch(
      () => props.isEnabled,
      async (newIsEnabled, oldIsEnabled) => {
        // 如果从禁用变为启用，且有批次ID，则加载数据
        if (!oldIsEnabled && newIsEnabled && props.batchId) {
          console.log('向量标注功能启用，加载特征配置')
          await loadFeatureConfig()
        }
      },
      { immediate: false }
    )

    // 图片放大相关方法
    const toggleImageZoom = index => {
      if (zoomedImageIndex.value === index) {
        // 如果点击的是当前放大的图片，则关闭放大
        zoomedImageIndex.value = null
      } else {
        // 否则放大点击的图片
        zoomedImageIndex.value = index
      }
    }

    const closeImageZoom = () => {
      zoomedImageIndex.value = null
    }

    const getZoomedImageSrc = () => {
      if (zoomedImageIndex.value === null) return ''
      const images = getPreviewImages()
      const imageData = images[zoomedImageIndex.value]
      return imageData?.image || ''
    }

    return {
      loading,
      dynamicFeatures,
      featureInput,
      containerRef,
      layoutClass,
      canAccept,
      isProcessing,
      processingButton,
      showDuplicateDialog,
      duplicateColorInfo,
      dimensionsResult,
      getFeatureAutoValue,
      getFeatureOptions,
      getDisplayValue,
      onFeatureChange,
      startAddingFeature,
      confirmAddFeature,
      cancelAddingFeature,
      handleAccept,
      handleStore,
      resetAllFeatures,
      getStatusText,
      getStatusBadgeClass,
      resetFeature,
      getPreviewImages,
      closeDuplicateDialog,
      getFieldValue,
      getAngleDisplayName,
      // 图片放大相关
      zoomedImageIndex,
      toggleImageZoom,
      closeImageZoom,
      getZoomedImageSrc,
    }
  },
}
</script>

<style scoped>
.vector-annotation-section {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.vector-disabled-notice {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  background: #fafafa;
  border-radius: var(--border-radius);
}

.disabled-notice-content {
  text-align: center;
  color: var(--text-secondary);
}

.disabled-icon-large {
  font-size: 48px;
  display: block;
  margin-bottom: 16px;
}

.disabled-notice-content h4 {
  margin: 0 0 8px 0;
  color: var(--text-color);
}

.disabled-notice-content p {
  margin: 4px 0;
  font-size: 14px;
}

.status-indicator {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 12px;
  font-size: 12px;
  font-weight: 500;
  color: white;
}

.badge-pending {
  background: #faad14;
}

.badge-success {
  background: var(--success-color);
}

.badge-error {
  background: var(--error-color);
}

.badge-empty {
  background: #d9d9d9;
  color: var(--text-color);
}

.badge-vectoring {
  background: #722ed1;
}

.badge-completed {
  background: #1890ff;
}

.feature-matrix {
  flex: 1;
  overflow-y: auto;
  container-type: inline-size;
  container-name: feature-matrix;
}

.matrix-header {
  display: flex;
  gap: 16px;
  margin-bottom: 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border-color);
  min-width: 0; /* 允许flex项目收缩 */
}

.image-preview {
  flex-shrink: 0;
  width: 80px;
}

.image-grid {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.image-slot {
  aspect-ratio: 1;
  border: 1px solid #e8e8e8;
  border-radius: 4px;
  overflow: hidden;
  background: #fafafa;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}

.image-slot.has-image {
  border-color: var(--primary-color);
}

.image-slot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.image-slot .placeholder {
  color: #999;
  font-size: 10px;
  text-align: center;
}

.angle-badge {
  position: absolute;
  top: 2px;
  left: 2px;
  background: rgba(0, 0, 0, 0.7);
  color: white;
  font-size: 8px;
  font-weight: bold;
  padding: 1px 3px;
  border-radius: 2px;
  z-index: 1;
}

.matrix-content {
  flex: 1;
  min-width: 0; /* 允许内容区域收缩 */
  overflow: hidden; /* 防止内容溢出 */
}

.matrix-content h4 {
  margin: 0 0 12px 0;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border-color);
  font-size: 14px;
}

.loading-placeholder,
.empty-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 200px;
  color: var(--text-secondary);
  font-size: 16px;
}

.loading-placeholder,
.empty-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 200px;
  color: var(--text-secondary);
  font-size: 16px;
}

.feature-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.feature-item {
  display: grid;
  grid-template-columns: 140px minmax(180px, 1fr) minmax(280px, 2fr) auto;
  grid-template-areas: 'label auto manual actions';
  align-items: center;
  column-gap: 12px;
  row-gap: 6px;
  padding: 8px;
  border: 1px solid #f0f0f0;
  border-radius: var(--border-radius);
  background: white;
  min-width: 0;
  position: relative;
}

/* 添加容器查询支持（如果浏览器支持） */
@container (max-width: 800px) {
  .feature-item {
    grid-template-columns: 120px minmax(150px, 1fr) minmax(200px, 2fr) auto;
    column-gap: 8px;
  }
  .select,
  .input {
    min-width: 120px;
  }
}

@container (max-width: 650px) {
  .feature-item {
    grid-template-columns: 100px minmax(120px, 1fr) minmax(160px, 2fr) auto;
    column-gap: 6px;
  }
  .select,
  .input {
    min-width: 100px;
  }
  .btn-add {
    padding: 5px 8px;
    font-size: 13px;
  }
}

@container (max-width: 550px) {
  .feature-item {
    grid-template-columns: 1fr;
    grid-template-areas:
      'label'
      'auto'
      'manual'
      'actions';
    row-gap: 8px;
    padding: 10px;
  }
  .feature-manual {
    border-left: none;
    padding-left: 0;
    border-top: 1px dashed var(--border-color);
    padding-top: 8px;
  }
  .feature-item > .btn-small {
    justify-self: start;
  }
  .select,
  .input {
    min-width: unset;
    width: 100%;
  }
}

.feature-label {
  grid-area: label;
  font-weight: 600;
  color: var(--text-color);
  font-size: 13px;
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 4px;
}

.required-mark {
  color: #ff4d4f;
  font-weight: bold;
}
.feature-auto {
  grid-area: auto;
  font-size: 12px;
  color: var(--text-secondary);
  background: #f5f5f5;
  padding: 4px 6px;
  border-radius: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.feature-manual {
  grid-area: manual;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  min-width: 0;
  border-left: 1px dashed var(--border-color);
  padding-left: 12px;
}
.feature-item > .btn-small {
  grid-area: actions;
  justify-self: end;
}

.dropdown-mode {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  flex: 1;
  min-width: 0;
}
.input-mode {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  flex: 1;
  min-width: 0;
}
.select {
  flex: 1;
  min-width: 140px;
  padding: 6px 8px;
  border: 1px solid var(--border-color);
  border-radius: 4px;
  background: white;
  font-size: 13px;
}
.input {
  flex: 1;
  min-width: 140px;
  padding: 6px 8px;
  border: 1px solid var(--border-color);
  border-radius: 4px;
  background: white;
  font-size: 13px;
}
.btn-add {
  padding: 6px 10px;
  background: var(--primary-color);
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  font-weight: bold;
  flex-shrink: 0;
}
.btn-add:hover {
  background: #0056b3;
}

.btn-cancel {
  padding: 6px 10px;
  background: #dc3545;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  font-weight: bold;
}

.btn-cancel:hover {
  background: #c82333;
}

.btn-confirm {
  padding: 6px 10px;
  background: #28a745;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  font-weight: bold;
}

.btn-confirm:hover {
  background: #218838;
}

.btn-small {
  padding: 3px 6px;
  background: #6c757d;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 11px;
  white-space: nowrap;
  flex-shrink: 0;
}

.btn-small:hover {
  background: #5a6268;
}

.vector-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px;
  border-top: 1px solid var(--border-color);
  background: #fafafa;
}

.toolbar-left {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}

.accept-hint {
  font-size: 12px;
  color: #ff4d4f;
  margin-left: 8px;
}

.processing-hint {
  font-size: 12px;
  color: #1890ff;
  margin-left: 8px;
  animation: pulse 1.5s infinite;
}

@keyframes pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.6;
  }
}

.toolbar-right {
  display: flex;
  align-items: center;
}

.btn-compact {
  padding: 6px 12px;
  font-size: 13px;
}

.btn-accept {
  background: #1890ff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
}

.btn-accept:hover {
  background: #096dd9;
}

.btn-accept:disabled {
  background: #d9d9d9;
  color: #999;
  cursor: not-allowed;
}

.btn-accept:disabled:hover {
  background: #d9d9d9;
}

/* 流光动画样式 */
.btn-accept.processing,
.btn-vectoring.processing {
  position: relative;
  overflow: hidden;
}

.btn-accept.processing::before,
.btn-vectoring.processing::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent);
  animation: shimmer 1.5s infinite;
  z-index: 1;
}

@keyframes shimmer {
  0% {
    left: -100%;
  }
  100% {
    left: 100%;
  }
}

.btn-vectoring {
  background: #722ed1;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
}

.btn-vectoring:hover {
  background: #531dab;
}

.btn-vectoring:disabled {
  background: #d9d9d9;
  color: #999;
  cursor: not-allowed;
}

.btn-vectoring:disabled:hover {
  background: #d9d9d9;
}

.btn-reset {
  background: #6c757d;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
}

.btn-reset:hover {
  background: #5a6268;
}

/* 基于类名的响应式布局（降级方案） */
.feature-item.layout-medium {
  grid-template-columns: 120px minmax(150px, 1fr) minmax(200px, 2fr) auto;
  column-gap: 8px;
}

.feature-item.layout-medium .select,
.feature-item.layout-medium .input {
  min-width: 120px;
}

.feature-item.layout-narrow {
  grid-template-columns: 100px minmax(120px, 1fr) minmax(160px, 2fr) auto;
  column-gap: 6px;
}

.feature-item.layout-narrow .select,
.feature-item.layout-narrow .input {
  min-width: 100px;
}

.feature-item.layout-narrow .btn-add {
  padding: 5px 8px;
  font-size: 13px;
}

.feature-item.layout-mobile {
  grid-template-columns: 1fr;
  grid-template-areas:
    'label'
    'auto'
    'manual'
    'actions';
  row-gap: 8px;
  padding: 10px;
}

.feature-item.layout-mobile .feature-manual {
  border-left: none;
  padding-left: 0;
  border-top: 1px dashed var(--border-color);
  padding-top: 8px;
}

.feature-item.layout-mobile > .btn-small {
  justify-self: start;
}

.feature-item.layout-mobile .select,
.feature-item.layout-mobile .input {
  min-width: unset;
  width: 100%;
}

.feature-item.layout-tiny {
  padding: 6px;
  row-gap: 4px;
}

.feature-item.layout-tiny .feature-label {
  font-size: 11px;
}

.feature-item.layout-tiny .feature-auto {
  font-size: 10px;
  padding: 2px 4px;
}

.feature-item.layout-tiny .select,
.feature-item.layout-tiny .input {
  font-size: 11px;
  padding: 4px 6px;
}

.feature-item.layout-tiny .btn-add,
.feature-item.layout-tiny .btn-small {
  font-size: 10px;
  padding: 3px 6px;
}

/* 媒体查询作为备用方案 */
@media (max-width: 800px) {
  .feature-item:not([class*='layout-']) {
    grid-template-columns: 120px minmax(150px, 1fr) minmax(200px, 2fr) auto;
    column-gap: 8px;
  }
  .feature-item:not([class*='layout-']) .select,
  .feature-item:not([class*='layout-']) .input {
    min-width: 120px;
  }
}

@media (max-width: 650px) {
  .feature-item:not([class*='layout-']) {
    grid-template-columns: 100px minmax(120px, 1fr) minmax(160px, 2fr) auto;
    column-gap: 6px;
  }
  .feature-item:not([class*='layout-']) .select,
  .feature-item:not([class*='layout-']) .input {
    min-width: 100px;
  }
  .feature-item:not([class*='layout-']) .btn-add {
    padding: 5px 8px;
    font-size: 13px;
  }
}

@media (max-width: 550px) {
  .feature-item:not([class*='layout-']) {
    grid-template-columns: 1fr;
    grid-template-areas:
      'label'
      'auto'
      'manual'
      'actions';
    row-gap: 8px;
    padding: 10px;
  }
  .feature-item:not([class*='layout-']) .feature-manual {
    border-left: none;
    padding-left: 0;
    border-top: 1px dashed var(--border-color);
    padding-top: 8px;
  }
  .feature-item:not([class*='layout-']) > .btn-small {
    justify-self: start;
  }
  .feature-item:not([class*='layout-']) .select,
  .feature-item:not([class*='layout-']) .input {
    min-width: unset;
    width: 100%;
  }
}

/* 图片放大相关样式 */
.image-slot img.zoomable {
  cursor: pointer;
  transition: transform 0.2s ease;
}

.image-slot img.zoomable:hover {
  transform: scale(1.05);
}

.image-zoom-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  backdrop-filter: blur(4px);
}

.image-zoom-container {
  position: relative;
  max-width: 90vw;
  max-height: 90vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.zoomed-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 8px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
  /* 移除 transform: scale(6)，让图片显示为原图1:1尺寸 */
  transition: transform 0.3s ease;
}

.zoom-close-btn {
  position: absolute;
  top: -40px;
  right: -40px;
  width: 32px;
  height: 32px;
  border: none;
  background: rgba(255, 255, 255, 0.9);
  color: #333;
  border-radius: 50%;
  font-size: 18px;
  font-weight: bold;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s ease;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}

.zoom-close-btn:hover {
  background: white;
  transform: scale(1.1);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
</style>
